<?php

namespace App\Kuafu\Order\Service;


use App\Kuafu\Base\Model\BaseModel;
use App\Kuafu\CouponExt\Enum\CouponExtEnum;
use App\Kuafu\CouponExt\Model\OrderCouponExtSplitModel;
use App\Kuafu\CouponPackage\Service\CouponPackageService;
use App\Kuafu\Customer\Enum\PlatformCodeEnum;
use App\Kuafu\Customer\Service\CustomerPlatformService;
use App\Kuafu\CustomerCoupon\Model\CustomerCouponModel;
use App\Kuafu\CustomPayment\Enum\CustomPaymentEnum;
use App\Kuafu\Order\Enum\CodeEnum;
use App\Kuafu\Order\Enum\OrderCodeEnum;
use App\Kuafu\Order\Enum\OrderInfoEnum;
use App\Kuafu\Order\Exceptions\OrderException;
use App\Kuafu\Order\Exceptions\OrderWaringException;
use App\Kuafu\Order\Model\ConsumerOrder;
use App\Kuafu\Order\Model\OrderCouponSplitModel;
use App\Kuafu\Order\Model\OrderDetailSplitModel;
use App\Kuafu\Order\Model\OrderDiscountSplitModel;
use App\Kuafu\Order\Model\OrderExternalSplitModel;
use App\Kuafu\Order\Model\OrderSplitModel;
use App\Kuafu\Order\Model\OrderUserInfoSplitModel;
use App\Kuafu\Pay\Model\PayStreamModel;
use App\Kuafu\Pay\Service\PayService;
use App\Kuafu\User\Exceptions\UserException;
use App\Kuafu\User\Service\AuthService;
use App\Library\SnowFlake\SnowFlake;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

/**
 * 订单锁服务
 * Class OrderOperateService
 * @package App\Kuafu\Order\Service
 */
class OrderLockService extends OrderBaseSplitService
{
    const LOCK_ORDER_SCAN_KEY = 'lock_order_scan_key:%s:%s';

    const LOCK_METHOD_TYPE_ORDER           = 'order';
    const LOCK_METHOD_TYPE_BAR_PAY         = 'barPay';
    const LOCK_METHOD_TYPE_MERCHANT_COUPON = 'merchantCoupon';

    public static function getOrderScanKey(string $shopId, string $orderId): string
    {
        return vsprintf(self::LOCK_ORDER_SCAN_KEY, [$shopId, $orderId]);
    }

    /**
     * 订单上锁处理
     *
     * @param string $shopId
     * @param string $orderId
     * @param string $method
     * @return void
     * @throws OrderWaringException
     */
    public static function lockOrderScan(string $shopId, string $orderId, string $method = self::LOCK_METHOD_TYPE_ORDER)
    {
        if (empty($orderId)) {
            return;
        }

        $key  = self::getOrderScanKey($shopId, $orderId);
        $time = 3;
        $lock = Redis::setNx($key, $method);
        if ($lock) {
            Redis::expire($key, $time);
        }

        // 无事发生
        if ($lock) {
            return;
        }

        switch ($method) {
            case 'order':
                throw new OrderWaringException(OrderCodeEnum::ERR_ORDER_HAS_BAR_PAYING,
                    OrderCodeEnum::CODE_TEXT[OrderCodeEnum::ERR_ORDER_HAS_BAR_PAYING] . ', 请等待用户支付完成后再操作订单。');
                break;
            case 'barPay':
                throw new OrderWaringException(OrderCodeEnum::ERR_ORDER_UPDATE_ERROR_LOCKED,
                    OrderCodeEnum::CODE_TEXT[OrderCodeEnum::ERR_ORDER_UPDATE_ERROR_LOCKED]);
                break;
            case 'merchantCoupon':
                throw new OrderWaringException(OrderCodeEnum::ERR_ORDER_CHECK_COUPON_LOCKED,
                    OrderCodeEnum::CODE_TEXT[OrderCodeEnum::ERR_ORDER_CHECK_COUPON_LOCKED]);
                break;
        }
    }

    /**
     * 释放锁
     *
     * @param string $shopId
     * @param string $orderId
     * @param string $method
     * @return void
     */
    public static function releaseOrderScan(
        string $shopId,
        string $orderId,
        string $method = self::LOCK_METHOD_TYPE_ORDER
    ) {
        if (empty($orderId)) {
            return;
        }

        $key = self::getOrderScanKey($shopId, $orderId);

        if ($method == Redis::get($key)) {
            Redis::del($key);
        }

        return;
    }
}
